package com.freestyle.common.support;

import com.freestyle.common.ResponseEntity;
import org.apache.dubbo.common.lang.Prioritized;
import org.apache.dubbo.metadata.definition.TypeDefinitionBuilder;
import org.apache.dubbo.metadata.definition.builder.TypeBuilder;
import org.apache.dubbo.metadata.definition.model.TypeDefinition;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;

import static org.apache.dubbo.common.utils.TypeUtils.*;

/**
 * Created by rocklee on 2022/3/28 21:25
 */
public class ResponseEntityTypeBuilder implements TypeBuilder , Prioritized {
  @Override
  public boolean accept(Type type, Class<?> clazz) {
    return clazz !=null&& ResponseEntity.class.isAssignableFrom(clazz);
  }
  @Override
  public int getPriority() {
    return -1;
  }
  @Override
  public TypeDefinition build(Type type, Class<?> clazz, Map<String, TypeDefinition> typeCache) {
    if (!(type instanceof ParameterizedType)) {
      return new TypeDefinition(clazz.getCanonicalName());
    }
    ParameterizedType parameterizedType = (ParameterizedType) type;
    Type[] actualTypeArgs = parameterizedType.getActualTypeArguments();
    int actualTypeArgsLength = actualTypeArgs == null ? 0 : actualTypeArgs.length;

    /*if (actualTypeArgsLength != 2) {
      throw new IllegalArgumentException(MessageFormat.format(
              "[ServiceDefinitionBuilder] Map type [{0}] with unexpected amount of arguments [{1}]."
                      + Arrays.toString(actualTypeArgs), type, actualTypeArgs));
    }*/

    String mapType = type.toString();

    TypeDefinition td = typeCache.get(mapType);
    if (td != null) {
      return td;
    }
    td = new TypeDefinition(mapType);
    typeCache.put(mapType, td);

    for (int i = 0; i < actualTypeArgsLength; i++) {
      Type actualType = actualTypeArgs[i];
      TypeDefinition item = null;
      Class<?> rawType = getRawClass(actualType);
      if (isParameterizedType(actualType)) {
        // Nested collection or map.
        item = TypeDefinitionBuilder.build(actualType, rawType, typeCache);
      } else if (isClass(actualType)) {
        item = TypeDefinitionBuilder.build(null, rawType, typeCache);
      }
      if (item != null) {
        td.getItems().add(item.getType());
      }
    }
    return td;
  }
}
